package com.sca.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sca.order.constant.RedisKeyConstant;
import com.sca.order.entity.Good;
import com.sca.order.entity.Order;
import com.sca.order.repository.OrderMapper;
import com.sca.order.service.GoodService;
import com.sca.order.service.OrderService;
import com.sca.order.utils.GuidGenerator;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author liuxianfei
 * @since 2020/11/3 11:50
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final GoodService goodService;
    private final RedisTemplate<String, Object> redisTemplate;
    private final Integer lock = 0;

    public OrderServiceImpl(GoodService goodService, RedisTemplate<String, Object> redisTemplate) {
        this.goodService = goodService;
        this.redisTemplate = redisTemplate;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean submit(Integer userId, Long goodId, Integer num) throws Exception {
        Good good = goodService.getById(goodId);
        if (good == null) {
            throw new Exception("测试异常回滚");
        }
        Order order = new Order();
        order.setUserId(userId);
        order.setOrderNum(GuidGenerator.generate());
        order.setGoodId(good.getId());
        order.setNum(num);
        order.setUnitPrice(good.getUnitPrice());
        order.setAmount(good.getUnitPrice().multiply(new BigDecimal(num)).setScale(4, RoundingMode.HALF_UP));
        return this.save(order);
    }

    @Override
    public Boolean submitForRedis(Integer userId, Long goodId, Integer num) {
        Good cache = (Good) redisTemplate.opsForValue().get(RedisKeyConstant.GOOD_STR_CACHE + goodId);
        if (cache == null) {
            synchronized (lock) {
                Good good = goodService.getById(goodId);
                if (good == null) {
                    return false;
                }
                redisTemplate.opsForValue().set(RedisKeyConstant.GOOD_STR_CACHE + goodId, good, 7200 + new Random().nextInt(60), TimeUnit.SECONDS);
                cache = good;
            }
        }
        Order order = new Order();
        order.setUserId(userId);
        String orderNum = GuidGenerator.generate();
        order.setOrderNum(orderNum);
        order.setGoodId(cache.getId());
        order.setNum(num);
        order.setUnitPrice(cache.getUnitPrice());
        order.setAmount(cache.getUnitPrice().multiply(new BigDecimal(num)).setScale(4, RoundingMode.HALF_UP));
        // redis本身可持久化，也可直接用消息队列发送到订单服务创建订单
        redisTemplate.opsForValue().set(RedisKeyConstant.ORDER_STR_SECKILL_TEMP + orderNum, order);
        return true;
    }

    @Override
    public List<Order> testShardingSql() {
        List<Order> orders = baseMapper.m1();
        orders.forEach(o -> System.out.println(JSON.toJSONString(o)));
        orders = baseMapper.m2(Lists.newArrayList(1L, 2L));
        orders.forEach(o -> System.out.println(JSON.toJSONString(o)));
        return orders;
    }

}
